#include <cassert>
#include <cfloat>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include "u1.h"
#include "coratings.h"
#include "symmetric_matrix.h"

using namespace std;

/**
 * Compute Abar and U as defined in
 * Bell, Koren (2007). Improved Neighbourhood-based Collaborative Filtering
 * (kdd-2007-cf-workshop on their website)
 *
 * Input is ratings / residuals data, sorted by movies, of the form:
 * movie_id:
 * user_id,rating[,...]
 * ...
 * where movie_ids must appear in ascending sorted order and, within each
 * movie block, user_ids must appear in ascending sorted order. (Here I mean
 * numeric order, not alphanumeric order.)
 *
 * It outputs two NUM_MOVIES by NUM_MOVIES symmetric matrices in binary
 * format (floats). Takes the file names for Abar and U as arguments.
 */

// ~100M ratings + ~18k separators for movies.
// But we allow more ratings for smoothed training sets.
#define MAX_RATINGS 200000000
id_rating_t<float> r[MAX_RATINGS];

// Functor for use with for_coratings that computes the matrix \bar{A} from
// Bell, Koren (2007). Improved Neighbourhood-based Collaborative Filtering
// (kdd-2007-cf-workshop on their website)
// Also compute the number of coratings U(i,j).
symmetric_matrix<float> Abar(NUM_MOVIES);
symmetric_matrix<float> U(NUM_MOVIES);
struct F_comp
{
  int pi, pj;

  void begin_pair(int id_i, int id_j) {
    pi = id_i - 1;
    pj = id_j - 1;
  }

  void corating(int id, float rating_i, float rating_j) {
    Abar(pi,pj) += rating_i * rating_j;
    U(pi,pj) += 1;
  }

  void end_pair() {
    // nothing
  }
} comp;

int main(int argc, char **argv)
{
  if (argc != 3) {
    TRACE<<"see comments for usage"<<endl;
    exit(EXIT_FAILURE);
  }
  string Abar_file = argv[1];
  string U_file = argv[2];
  TRACE<<"Will write Abar to "<<Abar_file<<endl;
  TRACE<<"Will write U to "<<U_file<<endl;

  TRACE<<"reading coratings"<<endl;
  size_t n = read_ratings_blocks(r, MAX_RATINGS, cin);
  assert(n < MAX_RATINGS);

  TRACE<<"computing"<<endl;
  for_coratings(r, n, comp);

  // When we accumulated Abar we didn't divide by U, as we must do.
  Abar.divide_by_if_not_zero(U);
  
  TRACE<<"done computing; writing files"<<endl;
  ofstream Abar_out(Abar_file.c_str());
  Abar.write_binary(Abar_out);
  Abar_out.close();
  ofstream U_out(U_file.c_str());
  U.write_binary(U_out);
  U_out.close();

  TRACE<<"done"<<endl;
  return 0;
}
/*
* Copyright (c) 2009 John Lees-Miller
* 
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
* 
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/

